/**
 * @fileOverview
 */

Karamu = Karamu || {};
Karamu.Controllers = Karamu.Controllers || {};

/**
 * @class
 * @requires jQuery, underscore.js, karamu.js
 * @param {Object} context the top-level controller object, e.g karamu
 */
Karamu.Controllers.Catalog = function(context){
    this.context = context;

    /**
     * @param {(Object|string)} element a jQuery object or jQuery selector for a single object to render into
     * @param {Object} options
     * @param {string} options.gadgetSelector e.g. '.gadget'
     * @param {string} options.dropzoneSelector e.g. '.dropzone'
     * @param {number} options.gadgetsPerPage default is 3
     * @public
     */
    this.render = function(element, options) {
        this.element = $(element);
        this.options = $.extend({
            gadgetSelector: '.gadget',
            dropzoneSelector: '.dropzone',
            gadgetsPerPage: 3
        }, options);

        /**
         * @param {?Object} xml XML document
         * @public
         */
        function setupSearch(xml) {
            // Parse and sort the category data
            var categories = $('categories', xml),
                categoryDetails = [];
            $('category', categories).each(function(i, category){
                var $category = $(category);
                categoryDetails.push($category.attr('name'));
            });
            categoryDetails.sort(function (a, b) {
                return a.localeCompare(b);
            });

            // Get the component
            var $select = $('select[name="gadget-categories"]', this.element);

            // Clear the current items
            $('option', $select).remove();

            // Populate the list
            $select.append(this.context.tmpl('select-option', {
                value: '*',
                label: 'All Categories'
            }));
            _.each(categoryDetails, function(category, j){
                $select.append(this.context.tmpl('select-option', {
                    value: category,
                    label: category
                }));
            }, this);

            // Remove previous, add event handler(s)
            $select.off().on({
                change: function(e) {
                    e.data.element.submit();
                },
            }, this);
        }

        /**
         * @param {?Object} xml XML document
         * @public
         */
        function setupCarousel(xml) {
            // Parse and sort the gadget data
            var gadgets = $('gadgets', xml),
                gadgetDetails = [];
            $('gadget', gadgets).each(function(i, gadget){
                var $gadget = $(gadget),
                    gadgetUrls = {
                        url:        $gadget.attr('url')        || '',
                        title_url:  $gadget.attr('title_url')  || '',
                        thumbnail:  $gadget.attr('thumbnail')  || '/karamu/gadgets/thumbnail.png',
                        screenshot: $gadget.attr('screenshot') || '/karamu/gadgets/screenshot.png'
                    };
                $.each(gadgetUrls, function(u, url){
                    if (url.indexOf('//') == 0) {
                        gadgetUrls[u] = window.location.protocol + url;
                    } else if (url.indexOf('/') == 0) {
                        gadgetUrls[u] = window.location.protocol + '//' + window.location.host + url;
                    }
                });
                gadgetDetails.push({
                    url: gadgetUrls.url,
                    thumbnail: gadgetUrls.thumbnail,
                    screenshot: gadgetUrls.screenshot,
                    title_url: gadgetUrls.title_url,
                    title: $gadget.attr('title') || '',
                    category: $gadget.attr('category') || '',
                    author_email: $gadget.attr('author_email') || '',
                    author: $gadget.attr('author') || '',
                    organization: $gadget.attr('organization') || '',
                    description: $gadget.attr('description') || '',
                    height: $gadget.attr('height') || ''
                });
            });
            gadgetDetails.sort(function (a, b) {
                return a.title.localeCompare(b.title);
            });

            // Wrap XML results in a carousel component
            var pages = Math.ceil(gadgetDetails.length / this.options.gadgetsPerPage);

            // Get the components
            $pager = $('.carousel .pagination ul', this.element);
            $inner = $('.carousel .carousel-inner', this.element);
            $close = $('.close-drawer', this.element);

            // Clear the current items
            $('li', $pager).remove();
            $('.item', $inner).remove();

            // Populate the pager, add the panes
            var target = '#' + this.element.attr('id') + '-carousel';

            for (var j = 0, k = pages; j < k; j++) {
                $inner.append(this.context.tmpl('pager-page'));
                $pager.append(this.context.tmpl('pager-number', {
                    target: target,
                    slideTo: j,
                    label: j + 1
                }));
            }
            $pager
                .prepend(this.context.tmpl('pager-arrow', {
                    target: target,
                    slide: 'prev',
                    label: '&laquo;'
                }))
                .append(this.context.tmpl('pager-arrow', {
                    target: target,
                    slide: 'next',
                    label: '&raquo;'
                }));

            $('.item:first-child', $inner).addClass('active');

            // Add the gadgets to the panes
            var width = 'span12';
            switch (this.options.gadgetsPerPage) {
                case 2: width = 'span6'; break;
                case 3: width = 'span4'; break;
                case 4: width = 'span3'; break;
                case 6: width = 'span2'; break;
            }
            for (var m = 0, n = gadgetDetails.length; m < n; m++) {
                this.context.controllers.preview.render(
                    $('.row-fluid:eq(' + Math.floor(m / this.options.gadgetsPerPage) + ')', $inner), {
                        width: width,
                        data: gadgetDetails[m]
                    }
                );
            }

            // Initialize the carousel functionality
            $carousel = $('.carousel', this.element).carousel({
                interval: false
            });

            // Prevent carousel controls from looping
            $carousel.preventLooping = function() {
                $('.pagination ul li:first', this).removeClass('disabled').attr('data-slide', 'prev');
                $('.pagination ul li:last', this).removeClass('disabled').attr('data-slide', 'next');
                if ($('.carousel-inner .item:first', this).hasClass('active')) {
                    $('.pagination ul li:first', this).addClass('disabled').removeAttr('data-slide');
                }
                if ($('.carousel-inner .item:last', this).hasClass('active')) {
                    $('.pagination ul li:last', this).addClass('disabled').removeAttr('data-slide');
                }
                return this;
            };
            $carousel.preventLooping().off().on('slid', function(){
                $carousel.preventLooping();
            });

            // Remove previous, add event handlers
            $close.off().on({
                click: function(e){
                    e.data.element.collapse('hide');
                }
            }, this);
        } // end function

        // Remove previous, add event handlers
        this.element.off().on({
            'show': function(e){
                var postData = {
                    rows: 30
                };
                e.data.fetch({
                    categories: true,
                    context: e.data,
                    success: setupSearch
                });
                e.data.fetch({
                    context: e.data,
                    data: postData,
                    success: setupCarousel
                });
            },
            'submit': function(e){
                e.preventDefault();
                var postData = {
                    text: $.trim($('input[name="gadget-search"]', e.data.element).val()),
                    category: $('select[name="gadget-categories"]', e.data.element).val(),
                    rows: 30
                }
                if (postData.text === '') {
                    delete postData.text;
                } else {
                    postData.text = '*' + postData.text + '*';
                }
                if (postData.category === '*') {
                    delete postData.category;
                }
                e.data.fetch({
                    context: e.data,
                    data: postData,
                    success: setupCarousel
                });
            }
        }, this);

        $('input[name="gadget-search"]', this.element).typeahead({
            context: this,
            source: function(query, process) {
                var postData = {
                    text: $.trim(query),
                    category: $('select[name="gadget-categories"]', this.element).val(),
                    rows: 30
                }
                if (postData.text === '') {
                    delete postData.text;
                } else {
                    postData.text = '*' + postData.text + '*';
                }
                if (postData.category === '*') {
                    delete postData.category;
                }
                this.options.context.fetch({
                    context: this.options.context,
                    data: postData,
                    success: function(xml){
                        var gadgets = $('gadgets', xml),
                            gadgetNames = [];
                        $('gadget', gadgets).each(function(i, gadget){
                            gadgetNames.push($(gadget).attr('title'));
                        });
                        gadgetNames.sort(function (a, b) {
                            return a.localeCompare(b);
                        });
                        process(gadgetNames);
                    },
                });
            },
            matcher: function (item) {
                if (item.toLowerCase().indexOf($.trim(this.query).toLowerCase()) != -1) {
                    return true;
                }
            },
            highlighter: function (item) {
                var regex = new RegExp( '(' + this.query + ')', 'gi' );
                return item.replace( regex, "<strong>$1</strong>" );
            }
        });

        $('#submitGadget', this.element).off().on({
            'submit': function(e){
                var postData = '<gadgets>' + $('textarea[name="gadget-submit"]').val() + '</gadgets>';
                e.data.push({
                    context: e.data.context,
                    data: postData,
                    success: function(xml){
                        if (console && console.log) console.log(xml);
                        $('gadgets', xml).each(function(i, gadget){
                            if (console && console.log) console.log($(gadget).attr('guid'));;
                        });
                    }
                });
            }
        }, this);
    };

    /**
     * @param {?Object} args
     * @param {?boolean} args.categories if present, use categories; otherwise gadgets
     * @param {?Function} args.complete
     * @param {?Object} args.context the top-level controller object, e.g karamu; if omitted, the XHR object is used
     * @param {?Object} args.data
     * @param {?Function} args.error
     * @param {?Function} args.success
     * @public
     */
    this.fetch = function(args){
        var services = (
                args.context.context.services
                    ? args.context.context.services
                    : args.context.services
            );
        var url = (
            args.categories
                ? services.categories
                : ($.isEmptyObject(args.data)
                    ? services.gadgets
                    : services.gadgets.replace('runMashup', '')
                )
            );
        $.ajax({
            cache: false,
            complete: args.complete,
            context: args.context,
            data: args.data,
            dataType: 'xml',
            error: args.error,
            success: args.success,
            type: 'GET',
            url: url
        });
    };

    /**
     * @param {?Object} args
     * @param {?boolean} args.categories if present, use categories; otherwise gadgets
     * @param {?Function} args.complete
     * @param {?Object} args.context the top-level controller object, e.g karamu; if omitted, the XHR object is used
     * @param {?Object} args.data
     * @param {?Function} args.error
     * @param {?Function} args.success
     * @public
     */
    this.push = function(args){
        var services = (
                args.context.context.services
                    ? args.context.context.services
                    : args.context.services
            );
        var url = (
            args.categories
                ? services.categories
                : services.gadgets
            );
        $.ajax({
            cache: false,
            complete: args.complete,
            context: args.context,
            data: args.data,
            dataType: 'xml',
            error: args.error,
            success: success,
            type: 'POST',
            url: url
        });
    };

};